home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: QTStdCompr.c
- //
- // Contains: Sample code for using QuickTime's standard image compression dialog routines.
- //
- // Written by: Tim Monroe
- // Based on existing code by Apple Developer Technical Support, which was itself
- // based on the code in Chapter 3 of Inside Macintosh: QuickTime Components.
- //
- // Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <4> 02/03/99 rtm reworked prompt and filename handling to remove "\p" sequences
- // <3> 04/23/98 rtm added extended procedures support; everything seems to work
- // fine on both Mac and Windows
- // <2> 04/22/98 rtm revised to personal coding style and made cross-platform
- // <1> 12/04/94 khs first file
- //
- // This sample code illustrates how to use QuickTime's standard image compression dialog routines
- // to get compression settings from the user and to compress an image using those settings. See
- // Chapter 3 of Inside Macintosh: QuickTime Components for complete information on the standard
- // image compression dialog routines.
- //
- // In this sample, we prompt the user to open an image file; then we display the standard image
- // compression dialog box and use the settings selected by the user to compress the image. The
- // Standard Image Compression Dialog Component currently supports three sources for the image:
- //
- // (1) a PICT handle
- // (2) a PICT file
- // (3) a pixel map
- //
- // The most general of these is the pixel map, so we'll use that throughout this sample. We can
- // create a pixel map by opening an image file and drawing it into an offscreen graphics world.
- // By using the graphics importer routines, we allow ourselves to handle ANY kind of image file for
- // which QuickTime supplies a graphics importer component. So, for free, we get support for PICT
- // files too.
- //
- // This sample also shows how to extend the basic user interface by installing a modal-dialog filter
- // function and a hook function to handle the optional custom button in the dialog box. If you don't
- // want this extended behavior, set gUseExtendedProcs to false.
- //
- // NOTES:
- //
- // *** (1) ***
- // Using the SCCompressImage function to compress a pixmap using some of the available compression
- // types (for instance, BMP) results in a block of compressed data that does not contain the required
- // headers. As a result, saving that data into a file results in an invalid image file. This is a
- // known limitation of QuickTime 3 and may be fixed in the future. Currently the only way to generate
- // these headers is to use a graphics importer to export the file as a BMP (or whatever) file. This
- // is NOT illustrated in this sample code.
- //
- // *** (2) ***
- // You can use the SCSetInfo function with the scSettingsStateType selector to retrieve a handle
- // containing the current compression settings; this might be useful if you were allowing the user
- // to compress a series of images and wanted to preserve the user's settings from one image to the
- // next (instead of reverting to the defaults for every image). Note, however, that the data in
- // that handle is byte-ordered according to the platform the code is running on. As a result, you
- // should not store that data in a file and expect that file to be valid on other platforms. To
- // get a handle of data in a platform-independent format, use the function SCGetSettingsAsAtomContainer
- // (introduced in QuickTime 3); to restore the settings in that handle, use the related function
- // SCSetSettingsAsAtomContainer.
- //
- //////////
-
- //////////
- //
- // header files
- //
- //////////
-
- #include "QTStdCompr.h"
-
- //////////
- //
- // global variables
- //
- //////////
-
- Boolean gUseExtendedProcs = true; // do we use extended procs with our dialog box?
- SCExtendedProcs gProcStruct;
-
- // our application's window-updating function
- extern void DoUpdateWindow (WindowRef theWindow, Rect *theRefreshArea);
-
- //////////
- //
- // QTStdCompr_PromptUserForImageFileAndCompress
- // Let the user select an image file and select its compression settings; then compress it.
- //
- //////////
-
- void QTStdCompr_PromptUserForImageFileAndCompress (void)
- {
- SFTypeList myTypeList;
- StandardFileReply myReply;
- Rect myRect;
- GraphicsImportComponent myImporter = NULL;
- ComponentInstance myComponent = NULL;
- GWorldPtr myImageWorld = NULL; // the graphics world we draw the image in
- PixMapHandle myPixMap = NULL;
- ImageDescriptionHandle myDesc = NULL;
- Handle myHandle = NULL;
- OSErr myErr = noErr;
-
- //////////
- //
- // have the user select an image file
- //
- //////////
-
- // kQTFileTypeQuickTimeImage means any image file readable by GetGraphicsImporterForFile
- myTypeList[0] = kQTFileTypeQuickTimeImage;
-
- StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- //////////
- //
- // get a graphics importer for the image file and determine the natural size of the image
- //
- //////////
-
- myErr = GetGraphicsImporterForFile(&myReply.sfFile, &myImporter);
- if (myErr != noErr)
- goto bail;
-
- myErr = GraphicsImportGetNaturalBounds(myImporter, &myRect);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // create an offscreen graphics world and draw the image into it
- //
- //////////
-
- myErr = NewGWorld(&myImageWorld, 0, &myRect, NULL, NULL, 0L);
- if (myErr != noErr)
- goto bail;
-
- // get the pixmap of the GWorld; we'll lock the pixmap, just to be safe
- myPixMap = GetGWorldPixMap(myImageWorld);
- if (!LockPixels(myPixMap))
- goto bail;
-
- // set the current port and draw the image
- GraphicsImportSetGWorld(myImporter, (CGrafPtr)myImageWorld, NULL);
- GraphicsImportDraw(myImporter);
-
- //////////
- //
- // display the standard image compression dialog box
- //
- //////////
-
- // open the standard compression dialog component
- myComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
- if (myComponent == NULL)
- goto bail;
-
- // set the picture to be displayed in the dialog box; passing NULL for the rect
- // means use the entire image; passing 0 for the flags means to use the default
- // system method of displaying the test image, which is currently a combination
- // of cropping and scaling; personally, I prefer scaling (your milage may vary)
- SCSetTestImagePixMap(myComponent, myPixMap, NULL, scPreferScaling);
-
- // install the custom procs, if requested
- // we can install two kinds of custom procedures for use in connection with
- // the standard dialog box: (1) a modal-dialog filter function, and (2) a hook
- // function to handle the custom button in the dialog box
- if (gUseExtendedProcs)
- QTStdCompr_InstallExtendedProcs(myComponent, (long)myPixMap);
-
- // request image compression settings from the user; in other words, put up the dialog box
- myErr = SCRequestImageSettings(myComponent);
- if (myErr == scUserCancelled)
- goto bail;
-
- //////////
- //
- // compress the image
- //
- //////////
-
- myErr = SCCompressImage(myComponent, myPixMap, NULL, &myDesc, &myHandle);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // save the compressed image in a new file
- //
- //////////
-
- QTStdCompr_PromptUserForDiskFileAndSaveCompressed(myHandle, myDesc);
-
- bail:
- if (gUseExtendedProcs)
- QTStdCompr_RemoveExtendedProcs();
-
- if (myPixMap != NULL)
- if (GetPixelsState(myPixMap) & pixelsLocked)
- UnlockPixels(myPixMap);
-
- if (myImporter != NULL)
- CloseComponent(myImporter);
-
- if (myComponent != NULL)
- CloseComponent(myComponent);
-
- if (myDesc != NULL)
- DisposeHandle((Handle)myDesc);
-
- if (myHandle != NULL)
- DisposeHandle(myHandle);
-
- if (myImageWorld != NULL)
- DisposeGWorld(myImageWorld);
- }
-
-
- //////////
- //
- // QTStdCompr_PromptUserForDiskFileAndSaveCompressed
- // Let the user select a disk file, then write the compressed image into that file.
- //
- //////////
-
- void QTStdCompr_PromptUserForDiskFileAndSaveCompressed (Handle theHandle, ImageDescriptionHandle theDesc)
- {
- StandardFileReply myReply;
- short myRefNum = -1;
- StringPtr myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveMoviePrompt);
- StringPtr myMovieFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName);
- OSErr myErr = noErr;
-
- // do a little sanity-checking....
- if ((theHandle == NULL) || (theDesc == NULL))
- goto bail;
-
- if ((**theDesc).dataSize > GetHandleSize(theHandle))
- goto bail;
-
- // prompt the user for a file to put the compressed image into; in theory, the name
- // should have a file extension appropriate to the type of compressed data selected by the user;
- // this is left as an exercise for the reader
- StandardPutFile(myMoviePrompt, myMovieFileName, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- HLock(theHandle);
-
- // create and open the file
- myErr = FSpCreate(&myReply.sfFile, kImageFileCreator, (**theDesc).cType, 0);
-
- if (myErr == noErr)
- myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myRefNum);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, 0);
-
- // now write the data in theHandle into the file
- if (myErr == noErr)
- myErr = FSWrite(myRefNum, &(**theDesc).dataSize, *theHandle);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, (**theDesc).dataSize);
-
- if (myErr == noErr)
- myErr = SetEOF(myRefNum, (**theDesc).dataSize);
-
- if (myRefNum != -1)
- myErr = FSClose(myRefNum);
-
- bail:
- free(myMoviePrompt);
- free(myMovieFileName);
-
- HUnlock(theHandle);
- }
-
-
- //////////
- //
- // QTStdCompr_InstallExtendedProcs
- // Install the modal-dialog filter function and the hook function.
- //
- //////////
-
- void QTStdCompr_InstallExtendedProcs (ComponentInstance theComponent, long theRefCon)
- {
- StringPtr myButtonTitle = QTUtils_ConvertCToPascalString(kButtonTitle);
-
- // the modal-dialog filter function can be used to handle any events that
- // the standard image compression dialog handler doesn't know about, such
- // as any update events for windows owned by the application
- gProcStruct.filterProc = NewSCModalFilterProc(QTStdCompr_FilterProc);
-
- // the hook function can be used to handle clicks on the custom button
- gProcStruct.hookProc = NewSCModalHookProc(QTStdCompr_ButtonProc);
-
- // in this example, we pass the pixel map handle as a refcon
- gProcStruct.refcon = theRefCon;
-
- // copy the string for our custom button into the extended procs structure
- BlockMove(myButtonTitle, gProcStruct.customName, 9);
-
- // set the current extended procs
- SCSetInfo(theComponent, scExtendedProcsType, &gProcStruct);
-
- free(myButtonTitle);
- }
-
-
- //////////
- //
- // QTStdCompr_RemoveExtendedProcs
- // Remove the modal-dialog filter function and the hook function.
- //
- //////////
-
- void QTStdCompr_RemoveExtendedProcs (void)
- {
- // clear out the extended procedures
- SCSetInfo((ComponentInstance)gProcStruct.refcon, scExtendedProcsType, NULL);
-
- // dispose of routine descriptors
- DisposeRoutineDescriptor(gProcStruct.filterProc);
- DisposeRoutineDescriptor(gProcStruct.hookProc);
- }
-
-
- //////////
- //
- // QTStdCompr_FilterProc
- // Filter events for a standard modal dialog box.
- //
- //////////
-
- PASCAL_RTN Boolean QTStdCompr_FilterProc (DialogPtr theDialog, EventRecord *theEvent, short *theItemHit, long theRefCon)
- {
- #pragma unused(theDialog, theItemHit, theRefCon)
- Boolean myEventHandled = false;
- WindowRef myWindow = NULL;
-
- switch (theEvent->what) {
- case updateEvt:
- // update the specified window, if it's behind the modal dialog
- myWindow = (WindowRef)theEvent->message;
- if ((myWindow != NULL) && (myWindow != theDialog)) {
- DoUpdateWindow(myWindow, &(**(myWindow->visRgn)).rgnBBox);
- myEventHandled = false; // so sayeth IM
- }
- break;
- }
-
- return(myEventHandled);
- }
-
-
- //////////
- //
- // QTStdCompr_ButtonProc
- // Handle item selections in the standard image compression dialog box.
- //
- // The theParams parameter is the component instance of the standard image compression
- // dialog component. Also, the theRefCon paramter is handle to our pixel map.
- //
- //////////
-
- PASCAL_RTN short QTStdCompr_ButtonProc (DialogPtr theDialog, short theItemHit, void *theParams, long theRefCon)
- {
- #pragma unused(theDialog)
- // in this sample code, we'll have the settings revert to their default values
- // when the user clicks on the custom button
- if (theItemHit == scCustomItem)
- SCDefaultPixMapSettings(theParams, (PixMapHandle)theRefCon, false);
-
- // always return the item passed in
- return(theItemHit);
- }
-